mod checked {
    use crate::checked;

    //     我们想要捕获的数学"错误"的类型。
    #[derive(Debug)]
    pub enum MathError {
        DivisionByZero,
        NegativeLogarithm,
        NegativeSquareRoot,
    }
    pub type MathResult<T> = Result<T, MathError>;

    pub fn div(x: f64, y: f64) -> MathResult<f64> {
        if y == 0.0 {
            // 此操作将失败,那么(与期让程序崩溃)不如把失败原因包裹在
            // `Err`中并返回。
            Err(MathError::DivisionByZero)
        } else {
            // 此操作成功,所以我们将结果包裹在`Ok`中并返回。
            Ok(x / y)
        }
    }
    pub fn sqrt(x: f64) -> MathResult<f64> {
        if x < 0.0 {
            Err(MathError::NegativeSquareRoot)
        } else {
            Ok(x.sqrt())
        }
    }
    pub fn ln(x: f64) -> MathResult<f64> {
        if x <= 0.0 {
            Err(MathError::NegativeLogarithm)
        } else {
            Ok(x.ln())
        }
    }
    //     `op(x, y)` === `sqrt(ln(x / y))`
    pub fn op(x: f64, y: f64) -> f64 {
        //     这是一个三层的match金字塔。
        match checked::div(x, y) {
            Err(why) =>panic!("{:?}", why),
            Ok(ratio) => match checked::ln(ratio) {
                Err(why) => panic!("{:?}", why),
                Ok(log_ratio) => match checked::sqrt(log_ratio) {
                    Err(why) => panic!("{:?}", why),
                    Ok(sqrt_log_ratio) => sqrt_log_ratio,
                },
            },
        }

    }
}

use checked::op;

fn main() {
//     这会失败吗？
    println!("{}", op(1.0, 10.0));

}
